package com.example.demo.controller;

import com.example.demo.model.LogInfo;
import com.example.demo.model.UserInfo;
import com.example.demo.service.LogInfoService;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fzykd
 * Date: 2022-11-01
 * Time: 9:38
 */

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private LogInfoService logInfoService;


    //注入事务相关的类
    @Autowired
    private DataSourceTransactionManager transactionManager; //数据源事务管理器
    @Autowired
    private TransactionDefinition transactionDefinition; //事务定义

    //此方法中 使用编程式事务
    @RequestMapping("/add")
    public int add(UserInfo userInfo){
        //非空校验
        if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername())||
                !StringUtils.hasLength(userInfo.getPassword())) return 0;
        //开启事务 也是获取事务
        TransactionStatus transactionStatus =
                transactionManager.getTransaction(transactionDefinition);
        int result = 0;
            result = userService.add(userInfo);
        System.out.println("受影响的行数: " + result);
        //提交事务 或者
        //transactionManager.rollback(transactionStatus); //回滚事务
        transactionManager.commit(transactionStatus);
        System.out.println("受影响的行数: " + result);
        return result;
    }

    //使用声明式的事务
    @Transactional(timeout = 1) //在方法之前，自动开启事务，在方法执行完成之后，自动提交事务，如果出现异常，自动回滚事务
    //timeout 单位是秒 事务超过了这个时间抛出异常 事务回滚
    @RequestMapping("/add1")
    public int add1(UserInfo userInfo) throws InterruptedException {
        //非空校验
        if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername())||
                !StringUtils.hasLength(userInfo.getPassword())) return 0;
        int result = userService.add(userInfo);
        System.out.println("受影响的行数: " + userInfo);
        //int num = 10/0; //出现异常事务回滚
        return result;
    }

    @Transactional //在方法之前，自动开启事务，在方法执行完成之后，自动提交事务，如果出现异常，自动回滚事务
    //timeout 单位是秒 事务超过了这个时间抛出异常 事务回滚
    @RequestMapping("/add2")
    public int add2(UserInfo userInfo){
        //非空校验
        if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername())||
                !StringUtils.hasLength(userInfo.getPassword())) return 0;
        int result = userService.add(userInfo);
        System.out.println("受影响的行数: " + userInfo);
        try{
            int num = 10/0; //出现异常事务回滚
        }catch (Exception e){
            //@Transactional 遇到了try/catch的时候 出现异常事务不会自动回滚
            //作为Spring来讲 既然添加了try/catch 说明是由能力和义务来处理这个异常
            // 应该自己会对这个异常处理相应的解决方法

            //解决办法1. 将这个异常重新抛出去 简单粗暴
            //throw e;

            //解决办法2. 手动的执行事务 来回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

        }

        return result;
    }


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @RequestMapping("/add3")
    public int add4(UserInfo userInfo){
        if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername()) ||
                                !StringUtils.hasLength(userInfo.getPassword())){
            return 0;
        }
        //添加用户信息
        int userResult = userService.add(userInfo);
        System.out.println("添加用户信息： " + userResult);
        //添加用户日志信息
        LogInfo logInfo = new LogInfo();
        logInfo.setName("添加用户");
        logInfo.setDesc("添加用户结果: " + userResult);
        logInfoService.add(logInfo);
        return userResult;
    }

}
